package com.jsftoolkit.gen.config.impl;

import static com.jsftoolkit.gen.config.DomUtils.*;

import java.util.Map;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;

import com.jsftoolkit.gen.config.FacesConfigEditor;

public class FacesConfigEditorImpl extends XmlEditor implements
		FacesConfigEditor {

	private final XPathExpression firstComponent;

	private final XPathExpression existingComponent;

	private XPathExpression firstRenderer;

	private XPathExpression renderKit;

	private XPathExpression existingRenderer;

	private XPathExpression renderKitById;

	public FacesConfigEditorImpl() throws XPathExpressionException,
			ParserConfigurationException {
		super();
		firstComponent = xpathFactory.newXPath().compile(
				"/faces-config/component[1]");

		existingComponent = xpathFactory.newXPath().compile(
				"/faces-config/component"
						+ "[child::component-class[normalize-space()=$class]]");
		firstRenderer = xpathFactory.newXPath().compile(
				"/faces-config/render-kit/renderer[1]");
		renderKit = xpathFactory.newXPath().compile(
				"/faces-config/render-kit[1]");

		renderKitById = xpathFactory.newXPath().compile(
				"/faces-config/render-kit["
						+ "child::renderKitId[normalize-space()=$id]]");

		existingRenderer = xpathFactory
				.newXPath()
				.compile(
						"/faces-config/render-kit/renderer"
								+ "[child::component-family[normalize-space()=$family] "
								+ "and child::renderer-type[normalize-space()=$rtype]]");

	}

	public Element registerRenderer(Document doc, String componentFamily,
			String rendererType, String rendererClass, String renderKitId)
			throws XPathExpressionException {
		Map<String, String> map = vars.get();
		map.clear();
		map.put("rtype", rendererType);
		map.put("family", componentFamily);

		Element root = doc.getDocumentElement();

		// find the render kit
		Element rkElem;
		if (renderKitId == null) {
			rkElem = (Element) findOrCreateElement(doc, root, renderKit,
					"render-kit", null);
		} else {
			map.put("id", renderKitId);
			rkElem = findOrCreateElement(doc, root, renderKitById,
					"render-kit", renderKit);
			setElementValue(doc, rkElem, "render-kit-id", renderKitId);
		}

		// find/create the renderer
		Element e = findOrCreateElement(doc, rkElem, existingRenderer,
				"renderer", firstRenderer);
		// update/create the renderer mapping elements
		setElementValue(doc, e, "component-family", componentFamily);
		setElementValue(doc, e, "renderer-type", rendererType);
		setElementValue(doc, e, "renderer-class", rendererClass);
		return e;
	}

	public Element registerComponent(Document doc, String componentType,
			String componentClass) throws XPathExpressionException {
		// prepare the variables
		Map<String, String> map = vars.get();
		map.clear();
		map.put("class", componentClass);

		Element root = doc.getDocumentElement();
		// find/create the component node
		Element e = findOrCreateElement(doc, root, existingComponent,
				"component", firstComponent);

		// update/create the type and class elements
		setElementValue(doc, e, "component-type", componentType);
		setElementValue(doc, e, "component-class", componentClass);

		return e;
	}

}
